# -*- shell-script -*-

# 33adapter_dt_nosysfs - Device-tree only adapter code.

# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2002, 2003, 2004, 2005

# Maintained by Martin Schwenke <martins@au.ibm.com>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    
# $Id: 33adapter_dt_nosysfs,v 1.1 2006/04/11 18:38:28 emunson Exp $

[ -n "$source_device_tree" -a -z "$sysfs_dir" ] || return 0

######################################################################

list_adapters ()
{
    # Sets: adapter_list
    adapter_list=""

    # Could do a single find for all adapter types (in
    # db_initialise_bus) and create a map, but BusyBox's find doesn't
    # support "-o", so we might as well do a find per type in this
    # function.

    ensure_directory "$db_bus_dt_dir"
    debug_cmd adapter_pci_legacy > "${db_bus_dt_dir}/lsvpd,adapter-pci-map"

    local dt_adapter_subdirs
    get_dt_adapter_subdirs

    local dt_adapter_subdir
    for das in $dt_adapter_subdirs ; do
	# Check to make sure we know the subtype - if not, ignore.
	local subtype
	dt_adapter_subdir_to_subtype "$das"
	if [ -z "$subtype" ] ; then
	    : "unknown device-tree adapter subdirectory \"${das}\""
	    continue
	fi

	local n
	for n in $(find "${source_device_tree}" -name "${das}@*") ; do
	    local bus_type bus_addr channel
	    dt_set_bus_info_hook "$n"
	    if [ -n "$bus_type" -a -n "$bus_addr" ] ; then
		# If channel then strip - we don't do channels right now.
		[ -n "$channel" ] && \
		    n="${n%/*}"  # dirname

		local bus_info="${bus_type}/${bus_addr}"

		# Already done (possibly via another channel)?
		local bus_alias
		bus_alias_get "$bus_info"
		[ -n "$bus_alias" ] && continue

		# This is a new one.
		local relnode="${db_bus_dt_subdir}/${n#${source_device_tree}/}"
		local node="${db_bus_dir}/${relnode}"
		bus_alias_set "$bus_info" "$node"
		ensure_directory "$node"
		echo -n "$subtype" >"${node}/lsvpd,subtype"
		dt_adapter_crosslink "$bus_type" "$bus_addr" \
		    "$subtype" "$node" "$n"

		adapter_list="${adapter_list} ${bus_info}"
	    else
		debug "list_adapters: failed to get bus_info for \"${n}\""
	    fi
	done
    done
}

get_names_adapter ()
{
    # Sets: names
    names=""

    local bus_type="$1"
    local bus_addr="$2"

    local node
    retrieve_node "${bus_type}/${bus_addr}"
    [ -n "$node" ] || return  ### !!!

    local f="${node}/lsvpd,names"
    [ -r "$f" ] && \
	read names <"$f"
}

######################################################################

set_dt_pci_domain_prop_hook ()
{
    # FIXME: Will the PCI link go away under 2.4?
    local d="${source_device_tree}/pci"
    local big_bus_num_flag="${source_device_tree}/rtas/ibm,read-pci-config"

    # Under 2.6, linux,pci-domain is always used.
    # FIXME: This code is no longer executed under 2.6.
    if [ -f "${d}/linux,pci-domain" ] ; then
	dt_pci_domain_prop="linux,pci-domain"
	return
    fi

    # Under 2.4, only take notice of these on big-bus-num machines.
    if [ -f "$big_bus_num_flag" ] ; then
	local i
	for i in "linux,phbnum" "linux,global-number" ; do
	    if [ -f "${d}/${i}" ] ; then
		dt_pci_domain_prop="$i"
		return
	    fi
	done
    fi
    
    # Sanity check.
    [ -f "$big_bus_num_flag" ] && \
	: "set_dt_pci_domain_prop_hook:" \
	"unable to determine PCI domain property name"
}

dt_set_bus_info_hook ()
{
    # Sets: bus_type, bus_addr, channel
    bus_type="" ; bus_addr="" ; channel=""
    
    local node="$1"

    local dom bus dev fun

    # Sanity check to ensure the loop below will terminate.
    [ "${node#${source_device_tree}}" = "$node" ] && return

    # Get property name for PCI domain on IBM pSeries big-bus-num machines.
    [ -z "$dt_pci_domain_prop" ] && set_dt_pci_domain_prop_hook

    local d="$node"

    while [ "$d" != "$source_device_tree" ] ; do
	local node_type=""
	[ -f "${d}/device_type" ] && read node_type <"${d}/device_type"

	case "$node_type" in
	    pci|ht)
	        # The range bottom of the 1st PCI bus-range we hit is the bus#.
		if [ -z "$bus" ] ; then
		    set -- $(tdump "${d}/bus-range")
		    bus_type="pci"
		    bus="$4"
		fi
		
	        # Found a PCI domain property: remember it & we're done!
		if [ -n "$dt_pci_domain_prop" -a \
		    -f "${d}/${dt_pci_domain_prop}" ] ; then
		    dom=$(tdump "${d}/${dt_pci_domain_prop}")
		    dom="${dom// /}"
		    break
		fi
		;;
	    isa)
		bus_type="$node_type"
		break
		;;
	    vdevice)
		bus_type="vio"
		break
		;;
	    *)
	        # Channel possibly only in original basename.
		[ -z "$channel" ] && channel="$dev"
		
	        # Adapter node?  Put dev[,fun] into $dev. 
		local bn="${d##*/}" # basename
		dev="${bn#*@}"
		;;	    
	esac

	d="${d%/*}" # dirname
    done

    case "$bus_type" in
	pci)
	    if [ -n "$bus" -a -n "$dev" ] ; then
		[ -n "$dom" ] || dom=0
		
		fun=0
		case "$dev" in
		    # Note: order is important here.  :-)
		    (*,*) fun="${dev#*,}" ; dev="${dev%,*}" ;;
		esac
		
		bus_addr=$(printf "%04x:%02x:%02x.%x" \
		    "0x${dom}" "0x${bus}" "0x${dev}" "0x${fun}")
	    fi
	    ;;
	vio|isa)
	    bus_addr="$dev"
	    ;;
    esac

    if [ -z "$bus_type" -o -z "$bus_addr" ] ; then
	bus_type=""
	bus_addr=""
	channel=""
    fi
}

######################################################################

dt_adapter_crosslink ()
{
    local bus_type="$1"
    local bus_addr="$2"
    local subtype="$3"
    local node="$4"
    local source_node="$5"

    case "$bus_type" in
	pci)
	    local names stype pci_addr name f dthw

	    while read stype pci_addr name rest ; do
		[ "$stype" = "$subtype" -a "$pci_addr" = "$bus_addr" ] && \
		    names="${names} ${name}"
	    done <"${db_bus_dt_dir}/lsvpd,adapter-pci-map"
	    names="${names# }"

	    # If Ethernet and ambiguous, filter on mac address.  Could
	    # do this above, but if the mac-address property isn't
	    # there, or is wrong, we'd still like to have found a
	    # unique match without it.
	    if [ "$subtype" = "ethernet" -a \
		-n "${names}" -a "${names}" != "${names% *}" ] ; then
		names=""

		local f dthw
		f="${source_node}/mac-address"
		if [ -r "$f" ] ; then
		    dthw=$(tdump "$f")
		    dthw="${dthw// /:}"

		    while read stype pci_addr name rest ; do
			[ "$stype" = "$subtype" -a \
			    "$pci_addr" = "$bus_addr" -a \
			    "$dthw" = "$rest" ] && \
			    names="${names} ${name}"
		    done <"${db_bus_dt_dir}/lsvpd,adapter-pci-map"
		    names="${names# }"
		fi
	    fi

	    # If no spaces in $names, just 1, so no ambiguity.
	    [ -n "${names}" -a "${names}" = "${names% *}" ] && \
		crosslink "adapter" "$subtype" "$node" "$names"
	    ;;
    esac
}


dt_adapter_subdir_to_subtype ()
{
    # Sets: subtype
    subtype=""

    local dt_adapter_subdir="$1"

    case "$dt_adapter_subdir" in
	(fibre-channel)                        subtype="fibre"              ;;
	(v-scsi)                               subtype="ibmvscsi"           ;;
	(k2-sata)                              subtype="sata"               ;;
	(l-lan)                                subtype="ibmveth"            ;;
	(ata-6)                                subtype="ata"                ;;
	(scsi|ethernet|ide|usb|display|serial) subtype="$dt_adapter_subdir" ;;
    esac
}

######################################################################

get_source_node_adapter ()
{
    # Sets: source_node
    source_node=""

    local node_type="$1"
    local bus_info="$2"
    local subtype="$3"

    local bus_alias
    bus_alias_get "$bus_info"
    [ -n "$bus_alias" ] || return 1 ### !!!

    source_node="${source_device_tree}${bus_alias#${db_bus_dt_dir}}"
}

